home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Workbench Add-On
/
Workbench Add-On - Volume 1.iso
/
BBS-Archive
/
Comm
/
term-source.lha
/
Extras
/
Source
/
term-Source.lha
/
Chat.c
< prev
next >
Wrap
C/C++ Source or Header
|
1995-02-13
|
14KB
|
708 lines
/*
** Chat.c
**
** Chat support code
**
** Copyright © 1990-1995 by Olaf `Olsen' Barthel
** All Rights Reserved
*/
#include "termGlobal.h"
// Maximum number of characters to enter per line
#define CHAT_LINE_SIZE 512
// Local data
STATIC struct List *ChatList;
STATIC struct Node *ChatNode;
STATIC STRPTR ChatBuffer,
ChatUndo,
ChatWork,
ChatTemp;
STATIC LONG ChatPosition;
STATIC Object *ChatGadget;
STATIC struct Hook ChatHook = { {NULL},(HOOKFUNC)ChatKey };
STATIC BOOL ChatWasActive;
/* ChatKey(register __a1 ULONG *Msg,register __a2 struct SGWork *Work):
*
* String gadget editing hook code. This is where all the
* magic happens.
*/
ULONG __saveds __asm
ChatKey(register __a1 ULONG *Msg,register __a2 struct SGWork *Work)
{
/* Someone activated the string gadget and
* hit a key.
*/
if(*Msg == SGH_KEY)
{
BOOL NeedChange = FALSE,
DidSomething = FALSE;
// Remember that this gadget was activated
Forbid();
ChatWasActive = TRUE;
Permit();
// Clear the history list when pressing Amiga+Del/Amiga+Backspace
if((Work -> IEvent -> ie_Qualifier & (AMIGARIGHT | AMIGALEFT)) && (Work -> IEvent -> ie_Code == DEL_CODE || Work -> IEvent -> ie_Code == BACKSPACE_CODE))
{
FreeList(ChatList);
NewList(ChatList);
ChatNode = NULL;
Work -> Actions &= ~(SGA_USE | SGA_BEEP);
return(TRUE);
}
/* Right-Amiga-key was pressed, release the
* string gadget so user may select a menu
* item.
*/
if((Work -> IEvent -> ie_Qualifier & AMIGARIGHT) && Work -> IEvent -> ie_Code < 96)
{
if(!(Work -> IEvent -> ie_Qualifier & (IEQUALIFIER_LSHIFT | IEQUALIFIER_RSHIFT)) && (Work -> IEvent -> ie_Code == KEYCODE_X || Work -> IEvent -> ie_Code == KEYCODE_Q))
return(TRUE);
else
{
Work -> Actions = (Work -> Actions & ~(SGA_USE | SGA_BEEP)) | SGA_END | SGA_REUSE;
return(TRUE);
}
}
// This looks like a function key. Send the corresponding macro.
if(Work -> IEvent -> ie_Code >= F01_CODE && Work -> IEvent -> ie_Code <= F10_CODE)
{
STRPTR String;
LONG Len,Index = Work -> IEvent -> ie_Code - F01_CODE;
Forbid();
// Pick the right macro
if(Work -> IEvent -> ie_Qualifier & IEQUALIFIER_CONTROL)
String = MacroKeys -> Keys[3][Index];
else
{
if(Work -> IEvent -> ie_Qualifier & (IEQUALIFIER_LALT | IEQUALIFIER_RALT))
String = MacroKeys -> Keys[2][Index];
else
{
if(Work -> IEvent -> ie_Qualifier & (IEQUALIFIER_LSHIFT | IEQUALIFIER_RSHIFT))
String = MacroKeys -> Keys[1][Index];
else
String = MacroKeys -> Keys[0][Index];
}
}
// Anything to send at all?
if(Len = strlen(String))
{
struct DataMsg *Msg;
if(Msg = (struct DataMsg *)CreateMsgItem(sizeof(struct DataMsg) + Len + 1))
{
Msg -> Type = DATAMSGTYPE_SERIALCOMMAND;
Msg -> Data = (STRPTR)(Msg + 1);
strcpy(Msg -> Data,String);
// Send the command
PutMsgItem(SpecialQueue,(struct MsgItem *)Msg);
}
}
Permit();
return(TRUE);
}
/* The user pressed the cursor-right key to
* move the cursor to the next word in the buffer.
*/
if(Work -> IEvent -> ie_Code == CURSORRIGHT && (Work -> IEvent -> ie_Qualifier & IEQUALIFIER_CONTROL))
{
if(Work -> BufferPos != Work -> NumChars)
{
WORD i,Position = -1;
for(i = Work -> BufferPos ; i < Work -> NumChars ; i++)
{
if(Work -> WorkBuffer[i] == ' ')
{
for( ; i < Work -> NumChars ; i++)
{
if(Work -> WorkBuffer[i] != ' ')
{
Position = i;
break;
}
}
break;
}
}
if(Position != -1)
Work -> BufferPos = Position;
else
Work -> BufferPos = Work -> NumChars;
Work -> EditOp = EO_MOVECURSOR;
}
return(TRUE);
}
/* The user pressed the cursor-right key to
* move the cursor to the previous word in the buffer.
*/
if(Work -> IEvent -> ie_Code == CURSORLEFT && (Work -> IEvent -> ie_Qualifier & IEQUALIFIER_CONTROL))
{
if(Work -> BufferPos)
{
WORD i,Position = -1;
for(i = Work -> BufferPos ; i >= 0 ; i--)
{
if(Work -> WorkBuffer[i] != ' ')
{
Position = i;
break;
}
}
if(Position == -1)
Position = 0;
if(Position)
{
i = Position;
Position = -1;
for( ; i >= 0 ; i--)
{
if(Work -> WorkBuffer[i] == ' ')
{
Position = i + 1;
break;
}
}
}
if(Position != -1)
Work -> BufferPos = Position;
else
Work -> BufferPos = 0;
Work -> EditOp = EO_MOVECURSOR;
}
DidSomething = TRUE;
}
/* The user pressed the cursor-up key to
* scroll through the command history.
*/
if(Work -> IEvent -> ie_Code == CURSORUP)
{
/* Shift key: jump to first command
* history entry.
*/
if(Work -> IEvent -> ie_Qualifier & (IEQUALIFIER_LSHIFT|IEQUALIFIER_RSHIFT))
{
if(ChatList -> lh_Head -> ln_Succ)
ChatNode = ChatList -> lh_Head;
else
ChatNode = NULL;
NeedChange = TRUE;
}
else
{
if(ChatNode)
{
if(ChatNode -> ln_Pred -> ln_Pred)
{
ChatNode = ChatNode -> ln_Pred;
NeedChange = TRUE;
}
}
else
{
if(ChatList -> lh_Head -> ln_Succ)
{
ChatNode = ChatList -> lh_TailPred;
NeedChange = TRUE;
}
}
}
DidSomething = TRUE;
}
/* The user pressed the cursor-down key to
* scroll through the command history.
*/
if(Work -> IEvent -> ie_Code == CURSORDOWN)
{
/* Shift key: jump to last command
* history entry.
*/
if(Work -> IEvent -> ie_Qualifier & (IEQUALIFIER_LSHIFT|IEQUALIFIER_RSHIFT))
{
if(ChatList -> lh_Head -> ln_Succ)
ChatNode = ChatList -> lh_TailPred;
else
ChatNode = NULL;
NeedChange = TRUE;
}
else
{
if(ChatNode)
{
if(ChatNode -> ln_Succ -> ln_Succ)
ChatNode = ChatNode -> ln_Succ;
else
ChatNode = NULL;
}
NeedChange = TRUE;
}
DidSomething = TRUE;
}
// Update the contents of the string gadget
if(NeedChange)
{
LONG Len;
if(ChatNode)
strcpy(Work -> WorkBuffer,ChatNode -> ln_Name);
else
Work -> WorkBuffer[0] = 0;
strcpy(Work -> StringInfo -> UndoBuffer,Work -> PrevBuffer);
Work -> StringInfo -> UndoPos = Work -> BufferPos;
Len = strlen(Work -> WorkBuffer);
if(Len < Work -> BufferPos)
Work -> BufferPos = Len;
Work -> NumChars = Len;
Work -> Actions = (Work -> Actions & ~SGA_BEEP) | SGA_USE | SGA_REDISPLAY;
}
// User pressed return?
if(Work -> Actions & SGA_END)
{
// Deactivate the gadget?
if(Work -> IEvent -> ie_Qualifier & (IEQUALIFIER_LSHIFT | IEQUALIFIER_RSHIFT))
{
Work -> Actions &= ~SGA_END;
Forbid();
ChatWasActive = FALSE;
Permit();
}
else
{
struct DataMsg *Msg;
LONG Len = Work -> NumChars;
// If any text was entered, add it to the history list
if(Work -> WorkBuffer[0])
{
BOOL AddIt = TRUE;
// Don't add duplicates
if(ChatNode)
{
if(!Stricmp(ChatNode -> ln_Name,Work -> WorkBuffer))
AddIt = FALSE;
}
// Allocate space for the text, then add it
if(AddIt)
{
struct Node *SomeNode;
if(SomeNode = (struct Node *)AllocVecPooled(sizeof(struct Node) + Len + 1,MEMF_ANY))
{
strcpy(SomeNode -> ln_Name = (STRPTR)(SomeNode + 1),Work -> WorkBuffer);
AddTail(ChatList,SomeNode);
}
}
}
ChatNode = NULL;
// Transfer the buffer
if(Msg = (struct DataMsg *)CreateMsgItem(sizeof(struct DataMsg) + Len + 3))
{
STRPTR Extra;
Msg -> Type = DATAMSGTYPE_SERIALCOMMAND;
Msg -> Data = (STRPTR)(Msg + 1);
strcpy(Msg -> Data,Work -> WorkBuffer);
// Add EOL characters
switch(Config -> TerminalConfig -> SendCR)
{
case EOL_CR:
Extra = "\r";
break;
case EOL_LF:
Extra = "\n";
break;
case EOL_CRLF:
Extra = "\r\n";
break;
case EOL_LFCR:
Extra = "\n\r";
break;
default:
Extra = NULL;
break;
}
if(Extra)
strcpy(Msg -> Data + Len,Extra);
// Clear the string gadget
Work -> WorkBuffer[0] = 0;
Work -> BufferPos = 0;
Work -> NumChars = 0;
Work -> Actions = (Work -> Actions & ~(SGA_BEEP | SGA_END)) | SGA_USE | SGA_REDISPLAY;
Work -> StringInfo -> UndoPos = 0;
Work -> StringInfo -> UndoBuffer[0] = 0;
// Send the line
PutMsgItem(SpecialQueue,(struct MsgItem *)Msg);
}
}
DidSomething = TRUE;
}
// Control character entered?
if(!DidSomething && Work -> Code && !(Work -> Code & 0xFFE0))
{
UBYTE Code = Work -> Code & 0x1F;
if(Code == '\t' && Work -> IEvent -> ie_Code != TAB_CODE)
return(TRUE);
if(Code != '\r' && Code != '\b')
{
struct DataMsg *Msg;
if(Code == ('S' & 0x1F) || Code == ('Q' & 0x1F))
{
if(Config -> SerialConfig -> xONxOFF)
{
Forbid();
if(Code == ('S' & 0x1F))
{
if(Status == STATUS_READY)
Status = STATUS_HOLDING;
}
else
{
if(Status == STATUS_HOLDING)
Status = STATUS_READY;
}
Permit();
}
if(!Config -> SerialConfig -> PassThrough)
return(TRUE);
}
if(Msg = (struct DataMsg *)CreateMsgItem(sizeof(struct DataMsg) + 2))
{
Work -> Actions &= ~SGA_USE;
Msg -> Type = DATAMSGTYPE_SERIALCOMMAND;
Msg -> Data = (STRPTR)(Msg + 1);
Msg -> Data[0] = Code;
Msg -> Data[1] = 0;
PutMsgItem(SpecialQueue,(struct MsgItem *)Msg);
}
}
}
return(TRUE);
}
else
{
if(*Msg == SGH_CLICK)
{
// Remember activation
Forbid();
ChatWasActive = TRUE;
Permit();
return(TRUE);
}
else
return(FALSE);
}
}
/* HideChatGadget():
*
* Remove the chat gadget, but don't free the buffers.
*/
VOID
HideChatGadget()
{
if(ChatGadget)
{
GetAttr(STRINGA_BufferPos,ChatGadget,(ULONG *)&ChatPosition);
RemoveGList(Window,(struct Gadget *)ChatGadget,1);
DisposeObject(ChatGadget);
ChatGadget = NULL;
}
}
/* DeleteChatGadget():
*
* Remove the chat gadget, also take care of the buffers.
*/
VOID
DeleteChatGadget()
{
HideChatGadget();
if(ChatBuffer)
{
FreeVecPooled(ChatBuffer);
ChatBuffer = NULL;
}
if(ChatList)
{
DeleteList(ChatList);
ChatList = NULL;
}
}
/* UpdateChatGadget():
*
* Redraw the chat gadget imagery.
*/
VOID
UpdateChatGadget()
{
if(ChatGadget)
{
struct RastPort *RPort = Window -> RPort;
LONG Left,Right,Top;
// Draw the separator bar
if(StatusWindow || Config -> ScreenConfig -> StatusLine == STATUSLINE_DISABLED)
Top = UserFontHeight;
else
Top = StatusDisplayHeight + UserFontHeight;
Top = Window -> Height - (Window -> BorderBottom + Top + 2);
Left = Window -> BorderLeft;
Right = Window -> Width - (Window -> BorderRight + 1);
SetAPen(RPort,DrawInfo -> dri_Pens[SHADOWPEN]);
Move(RPort,Left,Top);
Draw(RPort,Right,Top);
Top++;
SetAPen(RPort,DrawInfo -> dri_Pens[SHINEPEN]);
Move(RPort,Left,Top);
Draw(RPort,Right,Top);
// Redraw the gadget
RefreshGList((struct Gadget *)ChatGadget,Window,NULL,1);
}
}
/* ActivateChat(BOOL Reactivate):
*
* Activate the chat gadget.
*/
VOID __regargs
ActivateChat(BOOL Reactivate)
{
if(ChatGadget)
{
Forbid();
if(Reactivate)
Reactivate = ChatWasActive;
else
Reactivate = TRUE;
Permit();
if(Reactivate)
ActivateGadget((struct Gadget *)ChatGadget,Window,NULL);
}
}
/* CreateChatGadget():
*
* Create the chat gadget and add it to the main window.
*/
BOOL
CreateChatGadget()
{
ChatWasActive = TRUE;
// Allocate the history list
if(!ChatList)
{
if(!(ChatList = (struct List *)AllocVecPooled(sizeof(struct MinList),MEMF_ANY)))
return(FALSE);
else
NewList(ChatList);
ChatNode = NULL;
}
// Allocate the undo/work/editing buffers
if(!ChatBuffer)
{
if(!(ChatBuffer = (STRPTR)AllocVecPooled(5 * CHAT_LINE_SIZE,MEMF_ANY | MEMF_CLEAR)))
{
DeleteChatGadget();
return(FALSE);
}
else
{
ChatUndo = ChatBuffer + CHAT_LINE_SIZE;
ChatWork = ChatUndo + CHAT_LINE_SIZE;
ChatTemp = ChatWork + CHAT_LINE_SIZE;
}
}
// Finally create the gadget
if(!ChatGadget)
{
LONG Bottom = Window -> BorderBottom + UserFontHeight - 1;
if(!StatusWindow && Config -> ScreenConfig -> StatusLine != STATUSLINE_DISABLED && !Config -> ScreenConfig -> SplitStatus)
Bottom += StatusDisplayHeight;
if(!(ChatGadget = NewObject(NULL,STRGCLASS,
GA_Left, Window -> BorderLeft,
GA_Height, UserFontHeight,
GA_RelBottom, -Bottom,
GA_RelWidth, -(Window -> BorderLeft + Window -> BorderRight),
GA_TabCycle, FALSE,
STRINGA_TextVal, ChatBuffer,
STRINGA_MaxChars, CHAT_LINE_SIZE,
STRINGA_Buffer, ChatBuffer,
STRINGA_BufferPos, ChatPosition,
STRINGA_UndoBuffer, ChatUndo,
STRINGA_WorkBuffer, ChatWork,
STRINGA_NoFilterMode, TRUE,
// NOTE: This should really look like below,
// according to the BOOPSI documentation.
// STRINGA_Pens, ((LONG)DrawInfo -> dri_Pens[BACKGROUNDPEN] << 16) | DrawInfo -> dri_Pens[TEXTPEN],
// STRINGA_ActivePens, ((LONG)DrawInfo -> dri_Pens[BACKGROUNDPEN] << 16) | DrawInfo -> dri_Pens[TEXTPEN],
STRINGA_Pens, ((LONG)DrawInfo -> dri_Pens[BACKGROUNDPEN] << 8) | DrawInfo -> dri_Pens[TEXTPEN],
STRINGA_ActivePens, ((LONG)DrawInfo -> dri_Pens[BACKGROUNDPEN] << 8) | DrawInfo -> dri_Pens[TEXTPEN],
STRINGA_EditHook, &ChatHook,
TAG_DONE)))
{
DeleteChatGadget();
return(FALSE);
}
else
AddGList(Window,(struct Gadget *)ChatGadget,(UWORD)~0,1,NULL);
}
return(TRUE);
}